Add a DNS protocol analyzer tab (RFC 1035) - #1221
Open
joaopdadv wants to merge 13 commits into
Open
Conversation
Add a new `networking::dns` module that parses DNS messages directly from raw UDP/TCP payload bytes, with no external DNS crate: - `types.rs`: DnsMessage, DnsEvent, DnsQuestion, DnsRecord and the DnsRecordType / DnsRCode / DnsRData / DnsFlags enums, with Display impls. - `parser.rs`: `parse_dns(&[u8])` decoding the 12-byte header (bitwise flags), the Question section and Answer resource records, with compression-pointer support (RFC 1035 §4.1.4), RDATA interpreted per type (A, AAAA, CNAME/NS/PTR, MX, TXT, SOA) and defensive handling of malformed/truncated input (no panics). Includes 9 unit tests over fixed byte vectors (A query, compressed A response, AAAA, MX, NXDOMAIN, too-short, truncated, pointer loop). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Detect DNS traffic (UDP/TCP port 53) in the capture loop and parse the message from the transport payload, extracted from `headers.payload` before `analyze_headers` consumes the headers (the slice borrows `packet.data`, so it outlives the move). DNS over TCP's 2-byte length prefix is stripped before parsing. Parsed messages are pushed to a new `InfoTraffic::dns_events` vector, carried to the GUI on each tick and reset by `take_but_leave_something`; `refresh` intentionally ignores it (events are drained GUI-side). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a dedicated "DNS" tab to the running pages: - `gui::types::dns_state`: DnsState holds a bounded live log (VecDeque, cap 2000) of DnsEntry rows folded from the backend's DnsEvents. - `gui::pages::dns_page`: renders a header + scrollable table (Time, Q/R, Domain, Type, RCODE, Answers), newest first, with an empty-state placeholder; mirrors the inspect_page layout/styles. - Wire DnsState into Sniffer (field, construction, capture reset) and drain `msg.dns_events` into it in `refresh_data`. - Register RunningPage::Dns (tab label, next/previous, Globe icon) and dispatch it in `view`; enable the previously-disabled Globe icon. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Correlate each response with its originating query by transaction id and (client, server) endpoint pair to compute resolution latency, shown in a new "Latency" column on response rows. Count queries per domain and surface the top 5 in a "Top domains" ranking line on the DNS page. In-flight queries are bounded (cap 10k) to limit memory when queries go unanswered. Adds unit tests for latency correlation, orphan responses, and per-domain ranking. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add two dropdown filters to the DNS page: record type (A, AAAA, CNAME, MX, TXT, NS, PTR, SOA) and response code (NOERROR, NXDOMAIN, SERVFAIL, REFUSED, FORMERR, NOTIMP). The summary line shows the filtered count and an empty-state message distinguishes "no traffic yet" from "no matches". DnsFilter lives in gui state, is wired through new Message variants, and applied when rendering the log. Adds a unit test for the matching logic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A 2-packet Ethernet/IPv4/UDP capture (query + compressed A response for google.com) to reproduce and validate the DNS analyzer offline, with a README describing the expected output and the Wireshark cross-check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document how to build, run and try the DNS tab, including offline reproduction via the sample pcap, satisfying the "installation / execution / usage example" requirement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read docs/samples/dns_sample.pcap and run every packet through the exact production path (get_sniffable_headers -> payload extraction -> analyze_headers -> parse_dns), asserting the recovered query/response for google.com (type A, answer 8.8.8.8). Validates the full capture-to-parse chain, not just the parser in isolation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The ranking was laid out on a single horizontal row, which overflowed the page width. Render it as a title followed by one domain per line. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The record-type filter compared only the query type (QTYPE), so filtering by e.g. CNAME hid responses to A queries whose answer chain contains a CNAME (common for CDN/Vercel-hosted domains). Track the answer section's record types per entry and match the filter against the query type OR any answer record type. Adds a unit test covering a CNAME-in-answer response. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Answer(s) column showed only RDATA values, so a response to an A query whose answer chain contains a CNAME looked inconsistent when filtered by CNAME (the Type column shows the QTYPE, A). Prefix each answer with its record type, e.g. "CNAME cdn.example.net, A 1.2.3.4", matching dig/tcpdump and making the answer types visible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Complete the 12-byte DNS header parsing: read NSCOUNT (Authority) and ARCOUNT (Additional) record counts. The sections themselves are not expanded, but their counts are surfaced in the Answer(s) cell as a note (e.g. "[+1 add'l]"), which also reveals EDNS OPT records. Adds parser tests for the counts and the note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
|
Hey @joaopdadv thanks for your effort but I already have some plans regarding more precise name resolutions as part of #944 I'll keep this PR open for now and I'll probably take some inspiration, but given the importance of the feature and its impact I'll have to take more time to dig into it and possibly come up with a final implementation myself |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a dedicated DNS tab that parses the DNS protocol (RFC 1035)
directly from the bytes of UDP/TCP traffic on port 53 and presents it in real time.
Today Sniffnet only does reverse-DNS lookups to enrich displayed IPs and
identifies services by port number — there is no inspection of the DNS protocol
itself. This fills that application-layer gap.
What it does
&[u8](no external DNS crate), interpreting:(A, AAAA, CNAME, NS, PTR, MX, TXT, SOA).
ID + (client, server) endpoint pair.
query type or any answer record type, e.g. CNAME in a CNAME→A chain).
Implementation
src/networking/dns/module (parser.rs,types.rs).headers.payloadinparse_packets.rsbeforeanalyze_headersconsumes the headers, carried to the GUI via a newInfoTraffic::dns_eventsfield, and folded intogui::types::dns_state.RunningPage::Dnsandgui/pages/dns_page.rs; tabs render automatically.Testing
end-to-end test that runs
docs/samples/dns_sample.pcapthrough the realcapture-to-parse pipeline. Full suite: 185 passing, no new warnings.
tcpdumpon the same pcap (identical field interpretation).Notes / scope